import eState from "./eState";
import IState from "./IState";
import StateEvent from "./StateEvent";
import { Idle, Move, Attack, Squat, Dead, Jump, Dying } from "./States";
import AnimationController from "../../Controllers/AnimationController";

/**
 * 有限状态机
 * created by Five on 2018-12-5 09:55:42
 */

export default class FsMachine {
    private _current: IState = null;
    private _previous: IState = null;
    private _currentState: eState = eState.NONE;
    private _data: StateEvent = null;
    private _animNode: AnimationController = null;
    public get animNode(): AnimationController { return this._animNode; }
    public set animNode(value: AnimationController) { this._animNode = value; }
    public get Current(): IState { return this._current; }
    public set Current(value: IState) { this._current = value; }
    public get Previous(): IState { return this._previous; }
    public set Previous(value: IState) { this._previous = value; }
    public get CurrentData(): StateEvent { return this._data; }
    public set CurrentData(value: StateEvent) { this._data = value; }
    public get CurrentState(): eState { return this._currentState; }
    public set CurrentState(value: eState) { this._currentState = value; }

    _fsmPool: Map<eState, IState>;

    constructor(anim: AnimationController) {
        this._fsmPool = new Map<eState, IState>();
        this._fsmPool.set(eState.IDLE, new Idle(anim));
        this._fsmPool.set(eState.MOVE, new Move(anim));
        this._fsmPool.set(eState.JUMP, new Jump(anim));
        this._fsmPool.set(eState.ATTACK, new Attack(anim));
        this._fsmPool.set(eState.DAED, new Dead(anim));
        this._fsmPool.set(eState.SQAUT, new Squat(anim));
        this._fsmPool.set(eState.DYING, new Dying(anim));
        this._animNode = anim;
        this.Init();
    }

    public Init() {
        this.ChangeState(eState.IDLE);
        this._data = null;
    }

    private getState(es: eState): IState {
        if (this._fsmPool.has(es)) {
            return this._fsmPool.get(es);
        }
        return this.getState(eState.IDLE);
    }

    public ChangeState(es: eState, data?: StateEvent, preData?: StateEvent) {
        this.ChangeStateI(this.getState(es), data, preData);
    }

    public ChangeStateI(state: IState, data?: StateEvent, preData?: StateEvent) {
        if (state == null)
            return;
        if (this.Current != null && this.Current.StateID == state.StateID)
            return;
        if (this.Previous != null)
            this.Previous.Exit(preData);

        this.Previous = this.Current;
        this.CurrentState = state.StateID;
        this.CurrentData = data;
        this.Current = state;
        this.Current.Enter(data);
    }

    public Quit() {
        this.ChangeState(eState.IDLE);
    }

    public Back() {
        this.ChangeStateI(this.Previous);
    }

    public Execute() {
        if (this.CurrentData != null)
            this.CurrentData.Action(this.CurrentData.Datas);
    }

    public Tick(data: StateEvent = null) {
        if (this.Current != null)
            this.Current.Execute(data);
    }
}